/*!
这个文件主要构造了一个查询本地文件大小的 MCP AI 代理服务。
协议主要参考：https://modelcontextprotocol.io/specification/2025-03-26/server/tools
下面是主要功能：
 * 1. handle_initialize。用于响应客户端询问本服务的特性。
 * 2. handle_ping。用来响应客户端的保活。
 * 3. handle_toolist。用来响应客户端拉取功能清单。
 * 4. handle_tools_call。用来响应客户端调用具体函数。
 * 5. toolfunc_fileSizeRequest。用于处理实际功能的函数，本例子就1个，获取文件大小。
 * 6. func_others。不知名的函数请求都用这个函数处理。
 * 7. main。服务后端总入口
 * 8. defautl_Header。工具函数，返回Http头
 * 9. send_response。工具函数send_response。这个函数用来向AI客户端（比如AnythingLLM) 发送响应。
 * 10. error_happened。工具函数error_happened。这个函数用来向AI客户端（比如AnythingLLM) 发送错误消息。
*/
#include <QCoreApplication>
#include <QFile>
#include <QFileInfo>
#include <QJsonObject>
#include <QJsonDocument>
#include <QJsonParseError>
#include <QHttpServer>
#include <QTcpServer>
#include <QHostAddress>
#include <QTextStream>
#include <QJsonArray>
#include <QHttpServerResponse>
#include <QHttpHeaders>

//  MCP 简化流程
//================================================
//工具函数，返回Http头
QHttpHeaders defautl_Header();

//工具函数send_response。这个函数用来向AI客户端（比如AnythingLLM) 发送响应。
void send_response(QHttpServerResponder & response,QJsonObject obj,
				   QHttpServerResponder::StatusCode status = QHttpServerResponder::StatusCode::Ok);

//工具函数error_happened。这个函数用来向AI客户端（比如AnythingLLM) 发送错误消息。
void error_happened(QHttpServerResponder & response,QString reqID,QString message,int code );

//注册流程函数 01 : handle_initialize。用于响应客户端询问本服务的特性。
void handle_initialize(const QJsonObject & jsonObject, QHttpServerResponder & response) ;

//注册流程函数 02 : handle_ping。用来响应客户端的保活。
void handle_ping(const QJsonObject & jsonObject, QHttpServerResponder & response);

//注册流程函数 03 : handle_toolist。用来响应客户端拉取功能清单。
void handle_toolist(const QJsonObject & jsonObject, QHttpServerResponder & response);

//调用流程函数 04 : handle_tools_call。用来响应客户端调用具体函数。
void handle_tools_call(const QJsonObject & jsonObject, QHttpServerResponder & response);

// 实际功能函数
//==================================================
//用于处理实际功能的函数，本例子就1个，获取文件大小。
void toolfunc_fileSizeRequest(const QJsonObject & objreq, QHttpServerResponder & response);
//不知名的函数请求都用这个函数处理。
void func_others(const QJsonObject & jsonObject, QHttpServerResponder & response);

/*!
 * \brief main 服务后端总入口
 * \param argc 参数个数
 * \param argv 参数值。
 * \return 返回Qt的事件循环。
 */
int main(int argc, char *argv[]) {

  QCoreApplication app(argc, argv);

  // 创建服务器
  QHttpServer server;

  // 添加/mcp端点
  server.route("/mcp", [](const QHttpServerRequest& request, QHttpServerResponder& response) {
	QTextStream stm(stderr);
	// 解析JSON请求
	stm<<"\nClient:"<<QString::fromUtf8(request.body())<<"\n";
	stm.flush();
	QJsonParseError parseError;
	QJsonObject jsonObject = QJsonDocument::fromJson(request.body(),&parseError).object();
	if (parseError.error != QJsonParseError::NoError) {
	  error_happened(response,"","JSON Error", -32700);
	  return;
	}
	//提取方法名
	QString method = jsonObject["method"].toString();
	/*!
	 * 下面步骤遵循 MCP 协议，分为5步骤。
	 * */
	// 1.initialize
	if (method == "initialize") {
	  // 处理initialize方法
	  handle_initialize(jsonObject,response);
	  // 返回
	  return;
	}
	// 2.notifications/initialized
	else if (method.startsWith("notifications/initialized")) {
	  // 发送响应，状态码为Accepted
	  send_response(response,QJsonObject(),QHttpServerResponder::StatusCode::Accepted);
	}
	// 3.ping
	else if (method.startsWith("ping")) {
	  // 处理ping方法
	  handle_ping(jsonObject,response);

	}
	// 4.tools/list
	else if (method.startsWith("tools/list")) {
	  // 处理toolist方法
	  handle_toolist(jsonObject,response);
	}
	// 5.tools/call
	else if (method.contains("tools/call")) {
	  // 处理tools_call方法
	  handle_tools_call(jsonObject,response);
	}
	// 否则
	else {
	  // 发送错误响应，方法未找到
	  error_happened(response,jsonObject["id"].toString(),QString("Method '%1' not found").arg(method), -32601);
	}

  });

  auto tcpserver = new QTcpServer();
  if (!tcpserver->listen(QHostAddress::LocalHost,3456) || !server.bind(tcpserver)) {
	delete tcpserver;
	return -1;
  }

  return app.exec();
}

// 定义一个默认的HTTP头
QHttpHeaders defautl_Header()
{
  // 创建一个QHttpHeaders对象
  QHttpHeaders h;
  h.append("Content-Type","application/json");
  h.append("Cache-Control", "no-cache");
  h.append("Access-Control-Allow-Origin", "*");
  h.append("Access-Control-Allow-Methods", "POST");
  return h;
}

//发送响应函数
void send_response(QHttpServerResponder & response,QJsonObject obj,
				   QHttpServerResponder::StatusCode status)
{
  //创建响应对象
  QHttpServerResponse rp(status);
  //如果obj不为空，则将obj转换为json格式
  if (!obj.empty())
	rp = QHttpServerResponse(QJsonDocument(obj).toJson(),status);
  //设置响应头
  rp.setHeaders(defautl_Header());
  //发送响应
  response.sendResponse(rp);
  //Output
  QTextStream stm(stderr);
  stm <<  "\nServer:" <<QJsonDocument(obj).toJson()<<"\n";
  stm.flush();
}


void error_happened(QHttpServerResponder & response,QString reqID,QString message,int code )
{
  // 创建错误响应
  QVariantMap vm_err,vm_detail;
  vm_detail["code"]  =  code;
  vm_detail["message"]  = message;
  vm_err["jsonrpc"] = "2.0";
  if (reqID.length())
	vm_err["id"] = reqID;
  else
	vm_err["id"] = QJsonValue::Null;
  vm_err["error"] = vm_detail;
  QJsonObject mcpError = QJsonObject::fromVariantMap(vm_err);
  send_response(response,mcpError);
}


// 处理初始化请求
void handle_initialize(const QJsonObject & jsonObject, QHttpServerResponder & response) {
  // 定义capabilities对象，包含tools对象，tools对象包含listChanged属性，值为true
  QJsonObject capabilities{
	{"tools", QJsonObject({
							{"listChanged", true}
						  })}
  };
  // 定义serverInfo对象，包含name和version属性，值分别为"MyExample"和"1.0"
  QJsonObject serverInfo{
	{"name", "MyExample"},
	{"version", "1.0"}
  };
  // 定义result对象，包含capabilities、protocolVersion和serverInfo属性
  QJsonObject result{
	{"capabilities", capabilities},
	{"protocolVersion", "2025-03-26"},
	{"serverInfo", serverInfo}
  };

  // 定义responseJson对象，包含jsonrpc、id和result属性
  QJsonObject responseJson{
	{"jsonrpc", "2.0"},
	{"id", jsonObject["id"]},
	{"result", result}
  };
  // 发送响应
  send_response(response,responseJson);
}

// 处理ping请求
void handle_ping(const QJsonObject & jsonObject, QHttpServerResponder & response)
{
  // 创建响应json对象
  QJsonObject responseJson{
	{"jsonrpc", "2.0"}, // 设置jsonrpc版本
	{"id", jsonObject["id"]}, // 设置请求id
	{"result", QJsonObject()} // 设置响应结果
  };
  // 发送响应
  send_response(response,responseJson);
}

void handle_toolist(const QJsonObject & jsonObject, QHttpServerResponder & response)
{
  // 构建文件查询工具描述
  QJsonObject fileSizeQueryTool {
	{"name", "fileSizeQuery"},
	{"type", "function"},
	{"endpoint", "/mcp"},
	{"method", "POST"},
	{"description", "查询{filename}指定的文件的大小,包含1个参数，string类型，名称为 filename,意义就是要查询的路径。"},
	{"inputSchema", QJsonObject {
		{"type", QJsonValue("object")},
		{"properties",QJsonObject {
			{"filename", QJsonObject {{"type", "string"},{"description", "要查询大小的文件的完整路径"}}}
		  }}
	  }},
	{"returns", QJsonObject {
		{"type", "string"},
		{"description", "包含文件大小信息的格式化字符串"}
	  }}
  };
  // 创建工具列表数组
  QJsonArray toolList;
  toolList.append(fileSizeQueryTool);
  //toolList.append(otherTools);
  // 构建响应对象
  QJsonObject responseJson {
	{"jsonrpc", "2.0"},
	{"id", jsonObject["id"]},
	{"result", QJsonObject {
		{"tools", toolList}
	  }}
  };
  send_response(response,responseJson);
}


void handle_tools_call(const QJsonObject & jsonObject, QHttpServerResponder & response){
  // 检查jsonObject中是否包含params字段
  if (!jsonObject.contains("params"))
  {
	// 如果不包含，则调用error_happened函数，返回错误信息
	error_happened(response,jsonObject["id"].toString(),QString("Object params not found"), -32601);
	return;
  }
  // 检查params字段是否为对象
  if (!jsonObject["params"].isObject())
  {
	// 如果不是对象，则调用error_happened函数，返回错误信息
	error_happened(response,jsonObject["id"].toString(),QString("Params is not object."), -32601);
	return;
  }

  // 将params字段转换为对象
  QJsonObject op = jsonObject["params"].toObject();
  // 获取name字段的值
  QString md = op["name"].toString();
  // 如果name字段的值为fileSizeQuery，则调用toolfunc_fileSizeRequest函数
  if (md=="fileSizeQuery")
	toolfunc_fileSizeRequest(jsonObject, response);
  // 否则调用func_others函数
  else
	func_others(jsonObject, response);
}

void toolfunc_fileSizeRequest(const QJsonObject & objreq, QHttpServerResponder & response) {
  // 从请求参数中获取文件名
  QJsonObject objParas = objreq["params"].toObject();
  QJsonObject objArgs = objParas["arguments"].toObject();
  //只有一个参数，filename
  QString filename = objArgs["filename"].toString();
  QFileInfo info(filename);
  // 计算文件大小（MB）
  qint64 fileSize = -1;
  if (info.exists()) {
	fileSize = info.size();
  }
  // 创建响应
  QJsonArray arr_content;
  QJsonObject result {
	{"type","text"},
	{"text",QString("File %1 size is %2 Bytes.").arg(filename).arg(fileSize)}
  };
  arr_content.append(result);
  QJsonObject mcpResponse {
	{"jsonrpc", "2.0"},
	{"id", objreq["id"]},
	{"result",QJsonObject{
		{"isError",false},
		{"content",arr_content}
	  }
	}
  };
  send_response(response,mcpResponse);
}

void func_others(const QJsonObject & objreq, QHttpServerResponder & response)
{
  // 创建响应
  QJsonArray arr_content;
  QJsonObject result {
	{"type","text"},
	{"text",QString("Function is not supported.")}
  };
  arr_content.append(result);
  QJsonObject mcpResponse {
	{"jsonrpc", "2.0"},
	{"id", objreq["id"]},
	{"result",QJsonObject{
		{"isError",false},
		{"content",arr_content}
	  }
	}
  };
  send_response(response,mcpResponse);
}

